import 'dart:convert';
import 'dart:io';
import 'package:quiver/collection.dart';
import 'package:dio/dio.dart';
import 'package:flutter_tools/string_extension.dart';
import 'package:flutter_tools/wxlog.dart';
import 'models/error_model.dart';
import 'network_package.dart';
import 'refresh_token_proxy.dart';


class TokenInterceptor extends Interceptor {
    @override
  Future onResponse(Response response) {
      if (response != null && response.statusCode == HttpStatus.ok && response.data != null) {
        Map<String, dynamic> map = json.decode(response.data);

        int code = map['errorId'].toString().toInt;

        if (code == CusNetworkError.unauthorized) {
          RefreshTokenProxy.getInstance().refreshToken().then((value) {
            if (value) return reconnection(response);

            return super.onResponse(response);
          });
        }
      }

      return super.onResponse(response);
  }

  /// 鉴权失败后重连
  Future reconnection(Response response) {
    RequestOptions options = response.request;

    Map<String, dynamic> extra = options.extra;

    final Function _success = extra["success"];
    final RequestConfig _config = extra["config"];


    final String _url = options.path;
    final Map _params = options.method == "get" ? options.queryParameters : options.data;
    final CancelToken _cancelToken = options.cancelToken;

    if (_success == null) {  /// 无回调请求
      return Request().request(method: options.method, url: _url, params : _params, cancelToken: _cancelToken, config: _config);
    } else {
      final Function _error = extra["error"];
      final BaseModel _model = extra["model"];

      return Request().requestWithCallback(
        method: options.method == "get" ? Method.GET : Method.POST,
        url: _url,
        params: _params,
        model: _model,
        config: _config,
        cancelToken: _cancelToken,
        success: _success,
        error: _error
      );
    }
  }
}

class LoggingInterceptor extends Interceptor {
  LoggingInterceptor._();

  static LoggingInterceptor _loggingInterceptor;

  factory LoggingInterceptor() => _loggingInterceptor ??= LoggingInterceptor._();

  DateTime _startTime;
  DateTime _endTime;

  bool _netDataListenerSwitch = false;
  LruMap _resCache;

  void setNetDataListenerSwitch(bool flag, {cache: LruMap}) {
    _netDataListenerSwitch = flag;
    _resCache = cache;
  }

  @override
  Future onRequest(RequestOptions options) {

    _startTime = DateTime.now();

    wxLog('----------------Request Start----------------');
    if (options.queryParameters.isEmpty) {
      wxLog('RequestUrl: ${options.baseUrl}${options.path}' );
    } else {
      wxLog('RequestUrl: ${options.baseUrl}${options.path}?${Transformer.urlEncodeMap(options.queryParameters)}');
    }

    wxLog('RequestMethod: ${options.method}');
    wxLog('RequestHeaders: ${options.headers.toString()}');
    wxLog('RequestData: ${options.data.toString()}');

    return super.onRequest(options);
  }

  @override
  Future onResponse(Response response) {
    _endTime = DateTime.now();

    int duration = _endTime.difference(_startTime).inMilliseconds;

    if (_netDataListenerSwitch && _resCache != null) {
      _resCache[response.request.path] = {
        "method": response.request.method,
        "url": response.request.path,
        "header": response.headers.toString(),
        "options": response.request.queryParameters.isEmpty ? ' ${response.request.baseUrl}${response.request.path}' : '${response.request.baseUrl}${response.request.path}?${Transformer.urlEncodeMap(response.request.queryParameters)}',
        "status": response.statusCode,
        "data": response.data.toString()
      };

//      AbnormalToast.showAbnormalToast(errorPage: PageResponseList());
    }

    if(response.statusCode == HttpStatus.ok) {
      wxLog('Response is Success, the code is: ${response.statusCode} and response content is: ${response.data.toString()}');
    } else {
      wxLog('Response is Error, the code is: ${response.statusCode} and response content is: ${response.data.toString()}');
    }

    wxLog('--------------End----------takes: $duration ');

    return super.onResponse(response);
  }

  @override
  Future onError(DioError err) {
    wxLog('Error: ${err.toString()}');

    return super.onError(err);
  }

}